// ComHook.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include <stdlib.h>
#include <atlconv.h>
#include "ComHook.h"
#include "Config.h"
#include "HookUtilities.h"

LPOpenFile g_lpOpenFile = NULL;
LPCreateFileA g_lpCreateFileA = NULL;
LPCreateFileW g_lpCreateFileW = NULL;
LPCloseHandle g_lpCloseHandle = NULL;
LPWriteFile g_lpWriteFile = NULL;
LPWriteFileEx g_lpWriteFileEx = NULL;
LPReadFile g_lpReadFile = NULL;
LPReadFileEx g_lpReadFileEx = NULL;

LPBuildCommDCBA g_lpBuildCommDCBA = NULL;
LPBuildCommDCBW g_lpBuildCommDCBW = NULL;
LPBuildCommDCBAndTimeoutsA g_lpBuildCommDCBAndTimeoutsA = NULL;
LPBuildCommDCBAndTimeoutsW g_lpBuildCommDCBAndTimeoutsW = NULL;
LPClearCommBreak g_lpClearCommBreak = NULL;
LPClearCommError g_lpClearCommError = NULL;
LPEscapeCommFunction g_lpEscapeCommFunction = NULL;
LPGetCommConfig g_lpGetCommConfig = NULL;
LPGetCommMask g_lpGetCommMask = NULL;
LPGetCommModemStatus g_lpGetCommModemStatus = NULL;
LPGetCommProperties g_lpGetCommProperties = NULL;
LPGetCommState g_lpGetCommState = NULL;
LPGetCommTimeouts g_lpGetCommTimeouts = NULL;
LPGetDefaultCommConfig g_lpGetDefaultCommConfig = NULL;
LPPurgeComm g_lpPurgeComm = NULL;
LPSetCommBreak g_lpSetCommBreak = NULL;
LPSetCommConfig g_lpSetCommConfig = NULL;
LPSetCommMask g_lpSetCommMask = NULL;
LPSetCommState g_lpSetCommState = NULL;
LPSetCommTimeouts g_lpSetCommTimeouts = NULL;
LPSetDefaultCommConfig g_lpSetDefaultCommConfig = NULL;
LPSetupComm g_lpSetupComm = NULL;
LPTransmitCommChar g_lpTransmitCommChar = NULL;
LPWaitCommEvent g_lpWaitCommEvent = NULL;

HANDLE g_hSerialPortsHandles[128];

HANDLE CreateTemporaryFileForComPortHook()
{
	try
	{
		char strTempPath[MAX_PATH];
		if (!GetTempPathA(MAX_PATH, strTempPath))
		{
			LogWin32Error("Error: Couldn't retrieve temporary directory");
			throw;
		}
		char strTempFile[MAX_PATH];
		if (!GetTempFileNameA(strTempPath, "HCH", 0, strTempFile))
		{
			LogWin32Error("Error: Couldn't create temporary file");
			throw;
		}
		return g_lpCreateFileA(strTempFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
	}
	catch (...)
	{
		Log("Error while creating temporary file");
		return INVALID_HANDLE_VALUE;
	}
}

int GetComPortFromFileName(LPCSTR strFilename)
{
	try
	{
		// Filename too big, it cannot be a COM port filename
		if (strlen(strFilename) > MAX_PATH)
			return 0;

		char strFilenameCopy[MAX_PATH];
		strcpy(strFilenameCopy, strFilename);
		strupr(strFilenameCopy);

		char* lpstrFilename = strFilenameCopy;
		if (memcmp(lpstrFilename, "\\\\.\\", strlen("\\\\.\\")) == 0)
			lpstrFilename += strlen("\\\\.\\");
		if (memcmp(lpstrFilename, "COM", strlen("COM")) != 0)
			return 0;
		lpstrFilename += strlen("COM");
		for (char* c = lpstrFilename; *c > 0; c++)
			if (!isdigit(*c))
				return 0;
		return atoi(lpstrFilename);
	}
	catch (...)
	{
		Log("Error while getting COM port name from filename: %s", strFilename);
		return 0;
	}
}

int GetComPortFromHandle(HANDLE hFile)
{
	if (hFile != INVALID_HANDLE_VALUE)
	{
		for (int i = 0; i < sizeof(g_hSerialPortsHandles); i++)
			if (hFile == g_hSerialPortsHandles[i])
				return i + 1;
	}

	return 0;
}

HFILE WINAPI OpenFile_Hook(LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle)
{
	Log("Warning: Open File %s", lpFileName);
	return g_lpOpenFile(lpFileName, lpReOpenBuff, uStyle);
}

HANDLE WINAPI CreateFileA_Hook(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
	try
	{
		int iComPort = GetComPortFromFileName(lpFileName);

		if (iComPort && iComPort <= sizeof(g_hSerialPortsHandles))
		{
			// Already Open
			if (g_hSerialPortsHandles[iComPort - 1] != INVALID_HANDLE_VALUE)
			{
				Log("COM Port already open: %s", lpFileName);
				return INVALID_HANDLE_VALUE;
			}
			g_hSerialPortsHandles[iComPort - 1] = CreateTemporaryFileForComPortHook();
			Log("Hooking COM Port %d - Handle 0x%x - Filename: %s", iComPort, g_hSerialPortsHandles[iComPort - 1], lpFileName);
			return g_hSerialPortsHandles[iComPort - 1];
		}
		else
		{
			HANDLE handle = g_lpCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
			Log("Create File (0x%x): %s", handle, lpFileName);
			return handle;
		}
	}
	catch (...)
	{
		Log("Unhandled error in CreateFileA_Hook");
		return INVALID_HANDLE_VALUE;
	}
}

HANDLE WINAPI CreateFileW_Hook(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
	try
	{
		USES_CONVERSION;
		LPCSTR strAnsiFilename = W2A(lpFileName);

		int iComPort = GetComPortFromFileName(strAnsiFilename);

		if (iComPort && iComPort <= sizeof(g_hSerialPortsHandles))
		{
			// Already Open
			if (g_hSerialPortsHandles[iComPort - 1] != INVALID_HANDLE_VALUE)
			{
				Log("COM Port already open: %s", strAnsiFilename);
				return INVALID_HANDLE_VALUE;
			}
			g_hSerialPortsHandles[iComPort - 1] = CreateTemporaryFileForComPortHook();
			Log("Hooking COM Port %d - Handle 0x%x - Filename: %s", iComPort, g_hSerialPortsHandles[iComPort - 1], strAnsiFilename);
			return g_hSerialPortsHandles[iComPort - 1];
		}
		else
		{
			HANDLE handle = g_lpCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
			Log("Create File (0x%x): %s", handle, strAnsiFilename);
			return handle;
		}
	}
	catch (...)
	{
		Log("Unhandled error in CreateFileW_Hook");
		return INVALID_HANDLE_VALUE;
	}
}

BOOL WINAPI CloseHandle_Hook(HANDLE hObject)
{
	try
	{
		Log("=> Closing Handle 0x%X", hObject);

		int iComPort = GetComPortFromHandle(hObject);
		BOOL bResult = g_lpCloseHandle(hObject);

		if (iComPort)
		{
			if (bResult)
			{
				Log("COM Port %d closed - Handle 0x%X", iComPort, g_hSerialPortsHandles[iComPort - 1]);
				g_hSerialPortsHandles[iComPort - 1] = INVALID_HANDLE_VALUE;
			}
			else
				LogWin32Error("Error closing COM Port %d - Handle 0x%x", iComPort, g_hSerialPortsHandles[iComPort - 1]);
		}

		return bResult;
	}
	catch (...)
	{
		Log("Unhandled error in CloseHandle_Hook");
		return FALSE;
	}
}

BOOL WINAPI WriteFile_Hook(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
{
	try
	{
		Log("=> Writing to Handle 0x%X", hFile);

		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("COM Port %d Write: %s", iComPort, lpBuffer);
			*lpNumberOfBytesWritten = nNumberOfBytesToWrite;
			return TRUE;
		}

		return g_lpWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
	}
	catch (...)
	{
		Log("Unhandled error in WrtieFile_Hook");
		return FALSE;
	}
}

BOOL WINAPI WriteFileEx_Hook(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
	try
	{
		Log("=> Writing to Handle 0x%X", hFile);

		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: WriteFileEx called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpWriteFileEx(hFile, lpBuffer, nNumberOfBytesToWrite, lpOverlapped, lpCompletionRoutine);
	}
	catch (...)
	{
		Log("Unhandled error in WriteFileEx_Hook");
		return FALSE;
	}
}

BOOL WINAPI ReadFile_Hook(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
	try
	{
		Log("=> Reading from Handle 0x%X", hFile);

		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("COM Port %d Read", iComPort);
			lpNumberOfBytesRead = 0;
			return TRUE;
		}

		return g_lpReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
	}
	catch (...)
	{
		Log("Unhandled error in ReadFile_Hook");
		return FALSE;
	}
}

BOOL WINAPI ReadFileEx_Hook(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPOVERLAPPED lpOverlapped, LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
	try
	{
		Log("=> Reading from Handle 0x%X", hFile);

		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: ReadFileEx called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpReadFileEx(hFile, lpBuffer, nNumberOfBytesToRead, lpOverlapped, lpCompletionRoutine);
	}
	catch (...)
	{
		Log("Unhandled error in ReadFileEx_Hook");
		return FALSE;
	}
}

BOOL WINAPI BuildCommDCBA_Hook(LPCSTR lpDef, LPDCB lpDCB)
{
	try
	{
		/*int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
		return TRUE;
		}*/

		Log("Warning: BuildCommDCBA called %s", lpDef);

		return g_lpBuildCommDCBA(lpDef, lpDCB);
	}
	catch (...)
	{
		Log("Unhandled error in BuildCommDCBA_Hook");
		return FALSE;
	}
}

BOOL WINAPI BuildCommDCBW_Hook(LPCWSTR lpDef, LPDCB lpDCB)
{
	try
	{
		/*int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
		return TRUE;
		}*/

		Log("Warning: BuildCommDCBW called %s", lpDef);

		return g_lpBuildCommDCBW(lpDef, lpDCB);
	}
	catch (...)
	{
		Log("Unhandled error in BuildCommDCBW_Hook");
		return FALSE;
	}
}

BOOL WINAPI BuildCommDCBAndTimeoutsA_Hook(LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts)
{
	try
	{
		/*int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
		return TRUE;
		}*/

		Log("Warning: BuildCommDCBAndTimeoutsA called %s", lpDef);

		return g_lpBuildCommDCBAndTimeoutsA(lpDef, lpDCB, lpCommTimeouts);
	}
	catch (...)
	{
		Log("Unhandled error in BuildCommDCBAndTimeoutsA_Hook");
		return FALSE;
	}
}

BOOL WINAPI BuildCommDCBAndTimeoutsW_Hook(LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts)
{
	try
	{
		/*int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
		return TRUE;
		}*/

		Log("Warning: BuildCommDCBAndTimeoutsW called %s", lpDef);

		return g_lpBuildCommDCBAndTimeoutsW(lpDef, lpDCB, lpCommTimeouts);
	}
	catch (...)
	{
		Log("Unhandled error in BuildCommDCBAndTimeoutsW_Hook");
		return FALSE;
	}
}

BOOL WINAPI ClearCommBreak_Hook(HANDLE hFile)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: ClearCommBreak called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpClearCommBreak(hFile);
	}
	catch (...)
	{
		Log("Unhandled error in ClearCommBreak_Hook");
		return FALSE;
	}
}

BOOL WINAPI ClearCommError_Hook(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: ClearCommError called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpClearCommError(hFile, lpErrors, lpStat);
	}
	catch (...)
	{
		Log("Unhandled error in ClearCommError_Hook");
		return FALSE;
	}
}

BOOL WINAPI EscapeCommFunction_Hook(HANDLE hFile, DWORD dwFunc)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: EscapeCommFunction called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpEscapeCommFunction(hFile, dwFunc);
	}
	catch (...)
	{
		Log("Unhandled error in EscapeCommFunction_Hook");
		return FALSE;
	}
}

BOOL WINAPI GetCommConfig_Hook(HANDLE hCommDev, LPCOMMCONFIG lpCC, LPDWORD lpdwSize)
{
	try
	{
		int iComPort = GetComPortFromHandle(hCommDev);

		if (iComPort)
		{
			Log("Warning: GetCommConfig called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpGetCommConfig(hCommDev, lpCC, lpdwSize);
	}
	catch (...)
	{
		Log("Unhandled error in GetCommConfig_Hook");
		return FALSE;
	}
}

BOOL WINAPI GetCommMask_Hook(HANDLE hFile, LPDWORD lpEvtMask)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: GetCommMask called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpGetCommMask(hFile, lpEvtMask);
	}
	catch (...)
	{
		Log("Unhandled error in GetCommMask_Hook");
		return FALSE;
	}
}

BOOL WINAPI GetCommModemStatus_Hook(HANDLE hFile, LPDWORD lpModemStat)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: GetCommModemStatus called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpGetCommModemStatus(hFile, lpModemStat);
	}
	catch (...)
	{
		Log("Unhandled error in GetCommModemStatus_Hook");
		return FALSE;
	}
}

BOOL WINAPI GetCommProperties_Hook(HANDLE hFile, LPCOMMPROP lpCommProp)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: GetCommProperties called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpGetCommProperties(hFile, lpCommProp);
	}
	catch (...)
	{
		Log("Unhandled error in GetCommProperties_Hook");
		return FALSE;
	}
}

BOOL WINAPI GetCommState_Hook(HANDLE hFile, LPDCB lpDCB)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: GetCommState called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpGetCommState(hFile, lpDCB);
	}
	catch (...)
	{
		Log("Unhandled error in GetCommState_Hook");
		return FALSE;
	}
}

BOOL WINAPI GetCommTimeouts_Hook(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: GetCommTimeouts called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpGetCommTimeouts(hFile, lpCommTimeouts);
	}
	catch (...)
	{
		Log("Unhandled error in GetCommTimeouts_Hook");
		return FALSE;
	}
}

BOOL WINAPI GetDefaultCommConfig_Hook(LPCSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize)
{
	try
	{
		/*int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
		return TRUE;
		}*/

		Log("Warning: GetDefaultCommConfig called %s", lpszName);
		return g_lpGetDefaultCommConfig(lpszName, lpCC, lpdwSize);
	}
	catch (...)
	{
		Log("Unhandled error in GetDefaultCommConfig_Hook");
		return FALSE;
	}
}

BOOL WINAPI PurgeComm_Hook(HANDLE hFile, DWORD dwFlags)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: PurgeComm called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpPurgeComm(hFile, dwFlags);
	}
	catch (...)
	{
		Log("Unhandled error in PurgeComm_Hook");
		return FALSE;
	}
}

BOOL WINAPI SetCommBreak_Hook(HANDLE hFile)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: SetCommBreak called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpSetCommBreak(hFile);
	}
	catch (...)
	{
		Log("Unhandled error in SetCommBreak_Hook");
		return FALSE;
	}
}

BOOL WINAPI SetCommConfig_Hook(HANDLE hCommDev, LPCOMMCONFIG lpCC, DWORD dwSize)
{
	try
	{
		int iComPort = GetComPortFromHandle(hCommDev);

		if (iComPort)
		{
			Log("Warning: SetCommConfig called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpSetCommConfig(hCommDev, lpCC, dwSize);
	}
	catch (...)
	{
		Log("Unhandled error in SetCommConfig_Hook");
		return FALSE;
	}
}

BOOL WINAPI SetCommMask_Hook(HANDLE hFile, DWORD dwEvtMask)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: SetCommMask called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpSetCommMask(hFile, dwEvtMask);
	}
	catch (...)
	{
		Log("Unhandled error in SetCommMask_Hook");
		return FALSE;
	}
}

BOOL WINAPI SetCommState_Hook(HANDLE hFile, LPDCB lpDCB)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: SetCommState called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpSetCommState(hFile, lpDCB);
	}
	catch (...)
	{
		Log("Unhandled error in SetCommState_Hook");
		return FALSE;
	}
}

BOOL WINAPI SetCommTimeouts_Hook(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: SetCommTimeouts called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpSetCommTimeouts(hFile, lpCommTimeouts);
	}
	catch (...)
	{
		Log("Unhandled error in SetCommTimeouts_Hook");
		return FALSE;
	}
}

BOOL WINAPI SetDefaultCommConfig_Hook(LPCSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize)
{
	try
	{
		/*int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
		return TRUE;
		}*/

		Log("Warning: SetDefaultCommConfig called %s", lpszName);

		return g_lpSetDefaultCommConfig(lpszName, lpCC, dwSize);
	}
	catch (...)
	{
		Log("Unhandled error in SetDefaultCommConfig_Hook");
		return FALSE;
	}
}

BOOL WINAPI SetupComm_Hook(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: SetupComm called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpSetupComm(hFile, dwInQueue, dwOutQueue);
	}
	catch (...)
	{
		Log("Unhandled error in SetupComm_Hook");
		return FALSE;
	}
}

BOOL WINAPI TransmitCommChar_Hook(HANDLE hFile, char cChar)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: TransmitCommChar called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpTransmitCommChar(hFile, cChar);
	}
	catch (...)
	{
		Log("Unhandled error in TransmitCommChar_Hook");
		return FALSE;
	}
}

BOOL WINAPI WaitCommEvent_Hook(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped)
{
	try
	{
		int iComPort = GetComPortFromHandle(hFile);

		if (iComPort)
		{
			Log("Warning: WaitCommEvent called on COM Port %d", iComPort);
			return TRUE;
		}

		return g_lpWaitCommEvent(hFile, lpEvtMask, lpOverlapped);
	}
	catch (...)
	{
		Log("Unhandled error in WaitCommEvent_Hook");
		return FALSE;
	}
}

LPVOID g_paOriginalAdresses[8];
LPCSTR g_straHookNames[] = {"OpenFile", "CreateFileA", "CreateFileW", "CloseHandle", "WriteFile", "WriteFileEx", "ReadFile", "ReadFileEx",
	"BuildCommDCBA", "BuildCommDCBW", "BuildCommDCBAndTimeoutsA", "BuildCommDCBAndTimeoutsW", "ClearCommBreak", "ClearCommError",
	"EscapeCommFunction", "GetCommConfig", "GetCommMask", "GetCommModemStatus", "GetCommProperties", "GetCommState", "GetCommTimeouts",
	"GetDefaultCommConfig", "PurgeComm", "SetCommBreak", "SetCommConfig", "SetCommMask", "SetCommState", "SetCommTimeouts",
	"SetDefaultCommConfig", "SetupComm", "TransmitCommChar", "WaitCommEvent"};
LPVOID g_paHooks[] = {OpenFile_Hook, CreateFileA_Hook, CreateFileW_Hook, CloseHandle_Hook, WriteFile_Hook, WriteFileEx_Hook, ReadFile_Hook, ReadFileEx_Hook,
	BuildCommDCBA_Hook, BuildCommDCBW_Hook, BuildCommDCBAndTimeoutsA_Hook, BuildCommDCBAndTimeoutsW_Hook, ClearCommBreak_Hook,
	ClearCommError_Hook, EscapeCommFunction_Hook, GetCommConfig_Hook, GetCommMask_Hook, GetCommModemStatus_Hook,
	GetCommProperties_Hook, GetCommState_Hook, GetCommTimeouts_Hook, GetDefaultCommConfig_Hook, PurgeComm_Hook,
	SetCommBreak_Hook, SetCommConfig_Hook, SetCommMask_Hook, SetCommState_Hook, SetCommTimeouts_Hook, SetDefaultCommConfig_Hook,
	SetupComm_Hook, TransmitCommChar_Hook, WaitCommEvent_Hook};



BOOL InitialiseHooks(HMODULE hCallingModule)
{
	try
	{
		for (int i = 0; i < sizeof(g_hSerialPortsHandles); i++)
			g_hSerialPortsHandles[i] = INVALID_HANDLE_VALUE;

		SetInitialisationFatalError("");

		Hook("Kernel32.dll", hCallingModule, 8, g_straHookNames, g_paHooks, g_paOriginalAdresses);

		g_lpOpenFile = (LPOpenFile)g_paOriginalAdresses[0];
		g_lpCreateFileA = (LPCreateFileA)g_paOriginalAdresses[1];
		g_lpCreateFileW = (LPCreateFileW)g_paOriginalAdresses[2];
		g_lpCloseHandle = (LPCloseHandle)g_paOriginalAdresses[3];
		g_lpWriteFile = (LPWriteFile)g_paOriginalAdresses[4];
		g_lpWriteFileEx = (LPWriteFileEx)g_paOriginalAdresses[5];
		g_lpReadFile = (LPReadFile)g_paOriginalAdresses[6];
		g_lpReadFileEx = (LPReadFileEx)g_paOriginalAdresses[7];

		g_lpBuildCommDCBA = (LPBuildCommDCBA)g_paOriginalAdresses[8];
		g_lpBuildCommDCBW = (LPBuildCommDCBW)g_paOriginalAdresses[9];
		g_lpBuildCommDCBAndTimeoutsA = (LPBuildCommDCBAndTimeoutsA)g_paOriginalAdresses[10];
		g_lpBuildCommDCBAndTimeoutsW = (LPBuildCommDCBAndTimeoutsW)g_paOriginalAdresses[11];
		g_lpClearCommBreak = (LPClearCommBreak)g_paOriginalAdresses[12];
		g_lpClearCommError = (LPClearCommError)g_paOriginalAdresses[13];
		g_lpEscapeCommFunction = (LPEscapeCommFunction)g_paOriginalAdresses[14];
		g_lpGetCommConfig = (LPGetCommConfig)g_paOriginalAdresses[15];
		g_lpGetCommMask = (LPGetCommMask)g_paOriginalAdresses[16];
		g_lpGetCommModemStatus = (LPGetCommModemStatus)g_paOriginalAdresses[17];
		g_lpGetCommProperties = (LPGetCommProperties)g_paOriginalAdresses[18];
		g_lpGetCommState = (LPGetCommState)g_paOriginalAdresses[19];
		g_lpGetCommTimeouts = (LPGetCommTimeouts)g_paOriginalAdresses[20];
		g_lpGetDefaultCommConfig = (LPGetDefaultCommConfig)g_paOriginalAdresses[21];
		g_lpPurgeComm = (LPPurgeComm)g_paOriginalAdresses[22];
		g_lpSetCommBreak = (LPSetCommBreak)g_paOriginalAdresses[23];
		g_lpSetCommConfig = (LPSetCommConfig)g_paOriginalAdresses[24];
		g_lpSetCommMask = (LPSetCommMask)g_paOriginalAdresses[25];
		g_lpSetCommState = (LPSetCommState)g_paOriginalAdresses[26];
		g_lpSetCommTimeouts = (LPSetCommTimeouts)g_paOriginalAdresses[27];
		g_lpSetDefaultCommConfig = (LPSetDefaultCommConfig)g_paOriginalAdresses[28];
		g_lpSetupComm = (LPSetupComm)g_paOriginalAdresses[29];
		g_lpTransmitCommChar = (LPTransmitCommChar)g_paOriginalAdresses[30];
		g_lpWaitCommEvent = (LPWaitCommEvent)g_paOriginalAdresses[31];

		return TRUE;
	}
	catch (...)
	{
		Log("Exception thrown while initialising hooking dll");
		return FALSE;
	}
}

void UninitialiseHooks()
{
	try
	{
		LPVOID dummy[8];
		Hook("Kernel32.dll", NULL, 8, g_straHookNames, g_paOriginalAdresses, dummy);
		CloseLogFile();
	}
	catch (...)
	{
		Log("Exception thrown while uninitialising hooking dll");
	}
}
